#include <string>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include "uvsettings.h"
#include "uvstring.h"

namespace uv {
namespace settings {

SettingsMap args;
std::string help_string;

template<class T>
Value<T>::Value(T _default_value, std::string _tag, std::string _description) :
        has_value(false), value(_default_value), default_value(_default_value),
        tag(_tag) {
    help_str = _tag + "\t" + _description;
    help_string.append(help_str + "\n");
}

template<class T>
T Value<T>::getValue() {
    return value;
}

template<>
bool Value<bool>::getValue() {
    if (!has_value) {
        has_value = getBoolFromArgs(tag, value);
    }
    return value;
}

template<>
int Value<int>::getValue() {
    if (!has_value) {
        has_value = getIntFromArgs(tag, value);
    }
    return value;
}

template<>
std::string Value<std::string>::getValue() {
    if (!has_value) {
        has_value = getStringFromArgs(tag, value);
    }
    return value;
}

template<class T>
void Value<T>::setOverride(T _value) {
    value = _value;
}

template<class T>
void Value<T>::reset() {
    value = default_value;
}

template<class T>
std::string Value<T>::toString() {
    return help_str;
}

// Allow for bool values.
template class Value<bool>;
template class Value<int>;
template class Value<std::string>;

void main(int argc, char *argv[]) {
    for (int i = 0; i < argc; ++i) {
        if (!SETTINGS_IS_FLAG(argv[i])) {
            continue;
        }
        // Is an argument.
        char *tag = NULL, *value = NULL;
        if (SETTINGS_IS_USING_EQUALS(argv[i])) {
            tag = std::strtok(argv[i] + std::strlen(FLAG_PREFIX), "=");
            value = std::strtok(NULL, "=");
        } else if (i + 1 < argc) {
            tag = argv[i] + std::strlen(FLAG_PREFIX);
            value = argv[++i];
        }

        if (tag && value) {
            args[tag] = value;
        }
    }
}

std::string getHelpString() {
    return help_string;
}

bool getBoolFromArgs(const std::string& tag, bool& value) {
    SettingsMap::iterator it = args.find(tag);
    if (it != args.end()) {
        return string::getBool(it->second, value);
    }
    return false;
}

bool getIntFromArgs(const std::string& tag, int& value) {
    SettingsMap::iterator it = args.find(tag);
    if (it != args.end()) {
        if (string::isNumeric(it->second)) {
            value = (int) strtol(it->second.c_str(), NULL, 0);
            return true;
        }
    }
    return false;
}

bool getStringFromArgs(const std::string& tag, std::string& value) {
    SettingsMap::iterator it = args.find(tag);
    if (it != args.end()) {
        value = it->second;
        return true;
    }
    return false;
}

} // namespace settings
} // namespace uv
